package com.gitee.qdbp.base.shiro.filter;

import java.io.IOException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.shiro.session.SessionException;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.apache.shiro.web.filter.authc.AuthenticationFilter;
import org.apache.shiro.web.util.SavedRequest;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import com.gitee.qdbp.able.result.ResponseMessage;
import com.gitee.qdbp.base.i18n.IResultCodeI18nResolver;

/**
 * 注销登录过滤器, 支持JSON格式<br>
 * 配置了这个过滤器, 一律不允许访问, 必须执行注销过程<br>
 * 如果是JSON格式, 返回"操作成功", 否则跳转到失败页面
 *
 * <pre>
 * &lt;bean id="logoutFilter" class="{pkg}.JsonSupportLogoutFilter"&gt;
 *     &lt;property name="jsonHttpMessageConverter" ref="jsonHttpMessageConverter" /&gt;
 *     &lt;property name="logoutSuccessUrl" value="/" /&gt;
 * &lt;/bean&gt;
 * </pre>
 *
 * @author zhaohuihua
 * @version 150918
 */
public class JsonSupportLogoutFilter extends AuthenticationFilter {

    /** 日志对象 **/
    private static final Logger log = LoggerFactory.getLogger(JsonSupportLogoutFilter.class);

    private JsonHttpMessageConverter<ResponseMessage> converter;

    @Autowired(required = false)
    private IResultCodeI18nResolver resultCodeI18nResolver;

    /** whether to stay compatible with HTTP 1.0 clients. **/
    protected boolean redirectHttp10Compatible = true;

    /** 注销成功后的跳转页面 **/
    private String logoutSuccessUrl;

    /**
     * 一律不允许访问<br>
     * {@inheritDoc}
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        return false;
    }

    /**
     * 访问被拒绝的处理, 执行注销过程<br>
     * {@inheritDoc}
     */
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        Assert.notNull(converter, "JsonHttpMessageConverter must not be null");

        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;

        Subject subject = getSubject(req, resp);
        Object info = subject.getPrincipal();

        // 执行注销操作
        // try/catch added for SHIRO-298, @see LogoutFilter
        try {
            subject.logout();
        } catch (SessionException e) {
            log.debug("Encountered session exception during logout.", e);
        }

        if (log.isDebugEnabled()) {
            log.debug("Logout success, Account:{}", info);
        }

        if (converter.isJsonRequest(req)) {
            // 如果是JSON请求, 以JSON格式输出"操作成功"
            ResponseMessage rm = new ResponseMessage();
            if (resultCodeI18nResolver != null) {
                // 根据当时语言替换返回码对应的错误提示
                String message = resultCodeI18nResolver.getResultCodeMessage(rm.getCode());
                if (message != null) {
                    rm.setMessage(message);
                }
            }
            converter.write(rm, resp);
        } else {
            // 跳转到注销成功页面
            issueSuccessRedirect(req, resp);
        }
        return false;
    }

    @Override
    protected void issueSuccessRedirect(ServletRequest request, ServletResponse response) throws Exception {
        String fallbackUrl = getSuccessUrl();
        redirectToSavedRequest(request, response, fallbackUrl);
    }

    protected void redirectToSavedRequest(ServletRequest request, ServletResponse response, String fallbackUrl)
            throws Exception {
        String successUrl = null;
        boolean contextRelative = true;
        SavedRequest savedRequest = WebUtils.getAndClearSavedRequest(request);
        if (savedRequest != null && savedRequest.getMethod().equalsIgnoreCase(AccessControlFilter.GET_METHOD)) {
            successUrl = savedRequest.getRequestUrl();
            contextRelative = false;
        }

        if (successUrl == null) {
            successUrl = fallbackUrl;
        }

        if (successUrl == null) {
            throw new IllegalStateException("Success URL not available via saved request or via the "
                    + "successUrlFallback method parameter. One of these must be non-null for "
                    + "issueSuccessRedirect() to work.");
        }

        WebUtils.issueRedirect(request, response, successUrl, null, contextRelative, redirectHttp10Compatible);
    }

    @Override
    protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
        String loginUrl = getLoginUrl();
        WebUtils.issueRedirect(request, response, loginUrl, null, true, redirectHttp10Compatible);
    }

    /** whether to stay compatible with HTTP 1.0 clients. **/
    public boolean isRedirectHttp10Compatible() {
        return redirectHttp10Compatible;
    }

    /** whether to stay compatible with HTTP 1.0 clients. **/
    public void setRedirectHttp10Compatible(boolean redirectHttp10Compatible) {
        this.redirectHttp10Compatible = redirectHttp10Compatible;
    }

    /** 获取JsonHttpMessageConverter **/
    public JsonHttpMessageConverter<ResponseMessage> getJsonHttpMessageConverter() {
        return converter;
    }

    /** 设置JsonHttpMessageConverter **/
    public void setJsonHttpMessageConverter(JsonHttpMessageConverter<ResponseMessage> converter) {
        this.converter = converter;
    }

    /** 注销成功后的跳转页面 **/
    @Override
    public String getSuccessUrl() {
        return logoutSuccessUrl;
    }

    /** 注销成功后的跳转页面 **/
    public void setLogoutSuccessUrl(String logoutSuccessUrl) {
        this.logoutSuccessUrl = logoutSuccessUrl;
    }

}
